using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Tetris.Interfaces;

namespace Tetris.Levels
{
    public class GameGrid
    {
        private readonly int _width;
        private readonly int _height;
        public int FloorPixel { get; set; }
        public int LeftWallPixel { get; set; }
        public int RightWallPixel { get; set; }
        public int TopWallPixel { get; set; }
        public bool[][] Grid { get; set; }

        const int BlockWidth = 26;
        const int BlockHeight = 22;
        

        public GameGrid(int width, int height, int floorPixel, int leftWallPixel, int rightWallPixel, int topWallPixel)
        {
            _width = width;
            _height = height;
            FloorPixel = floorPixel;
            LeftWallPixel = leftWallPixel;
            RightWallPixel = rightWallPixel;
            TopWallPixel = topWallPixel;

            // initialize grid
            Grid = new bool[height][];
            for (int i = 0; i < height; i++)
            {
                Grid[i] = new bool[width];
            }
        }

        private int GetGridColumn(ITile tile)
        {
            int relativePositionX = (int)(tile.Position.X - LeftWallPixel);
            return relativePositionX / BlockWidth;
        }

        private int GetGridRow(ITile tile)
        {
            int relativePositionY = (int)(tile.Position.Y - TopWallPixel);
            return relativePositionY / BlockHeight;
        }

        private void AddStoppedBlock(IBlock block)
        {
            foreach (ITile tile in block.Tiles)
            {
                int gridRow = GetGridRow(tile);
                tile.SetRow(gridRow);
                Grid[gridRow][GetGridColumn(tile)] = true;
            }
        }

        public List<int> MoveBlock(IBlock block)
        {
            // block reached bottom?
            if (block.Tiles.Any(part => GetGridRow(part) >= _height - 1))
            {
                return StopBlock(block);
            }

            // block touches block below? -> stop
            foreach (ITile part in block.Tiles)
            {
                int gridRow = GetGridRow(part);
                int gridColumn = GetGridColumn(part);

                if (Grid[gridRow + 1][gridColumn])
                {
                    return StopBlock(block);
                }
            }
            return null;
        }

        private List<int> StopBlock(IBlock block)
        {
            block.HasStopped = true;
            AddStoppedBlock(block);
            return CheckForCompleteLines();
        }


        public List<int> CheckForCompleteLines()
        {
            // foreach row
            List<int> result = new List<int>();
            for (int row = 0; row < _height; row++)
            {
                bool completeLine = true;
                // foreach column
                for(int column = 0; column < _width; column++)
                {
                    completeLine &= Grid[row][column];
                }
                if ( completeLine )
                {
                    result.Add(row);
                }
            }

            // move every row above highest completed row down number of completed rows
            if (result.Count > 0)
            {
                int max = result.Max();
                for (int row = max; row >= 0; row-- )
                {
                    if (row - result.Count > 0)
                        Grid[row] = GetRowValues(row - result.Count);
                    else
                    {
                        Grid[row] = GetEmptyRow();
                    }
                    
                }
            }
            return result;
        }

        private bool[] GetRowValues(int row)
        {
            bool[] result = new bool[_width];
            for (int column = 0; column < _width; column++)
            {
                result[column] = Grid[row][column];
            }
            return result;
        }

        private bool[] GetEmptyRow()
        {
            bool[] result = new bool[_width];
            for (int i = 0; i < _width; i++)
            {
                result[i] = false;
            }
            return result;
        }

        public bool CanMoveLeft(IBlock fallingBlock)
        {
            bool canMoveLeft = true;
            foreach (ITile part in fallingBlock.Tiles)
            {
                int columnIfMovedLeft = GetGridColumn(part) - 1;
                if (columnIfMovedLeft < 0) return false;
                canMoveLeft &= !Grid[GetGridRow(part)][columnIfMovedLeft];
            }
            return canMoveLeft;
        }

        public bool CanMoveRight(IBlock fallingBlock)
        {
            bool canMoveRight = true;
            foreach (ITile part in fallingBlock.Tiles)
            {
                int columnIfMovedRight = GetGridColumn(part) + 1;
                if (columnIfMovedRight >= _width) return false;
                canMoveRight &= !Grid[GetGridRow(part)][columnIfMovedRight];
            }
            return canMoveRight;
        }

        public bool CanRotate(IBlock fallingBlock)
        {
            // TODO
            return true;
        }
    }
}